热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

K8S实战(十)|Service

前言

前言

Pod 已经成功运行起来了,但是有两个问题。

一是这些 Pod 无法从集群外部直接访问到,二是 Pod 出现故障自愈后,IP 会发生变化。

如何解决这两个问题,这里有一个非常重要的概念:Service

更新历史

  • 20200625 - 初稿 - 左程立
  • 原文地址 - https://blog.zuolinux.com/2020/06/25/about-service.html

Service 的意义和特点

  1. 对一组 Pod 提供负载均衡(工作在 TCP/UDP 4 层)
  2. 防止 Pod 更换 IP 失联,即服务发现
  3. 通过 label selector 关联 Pod

Service 工作原理

Service 是由 kube-proxy 组件加上 iptables/LVS 共同实现。说白了就是通过 kube-proxy 生成了一堆 iptables 规则,通过 iptables 规则来转发数据。

iptables 转发:

  1. K8S 默认的转发设置。
  2. 选择后端 Pod 为随机选择。
  3. 当 Pod 没有响应,连接会失败,并没有健康检查机制。
  4. 需要配合 Pod 就绪探测器来确保访问到健康的 Pod。
  5. 当集群规模达到上万个服务时,iptables 转发效率会显著降低。

LVS转发:

  1. 基于内核哈希表,性能强大,具有更高网络吞吐量。
  2. 适用于 Pod 量级大,转发规则更多的大规模集群。
  3. LVS 支持更多的 Pod 负载均衡调度算法。
  4. LVS 只负责负载均衡和代理功能,剩余的包过滤和SNAT等操作还是需要 iptables 处理,但这些操作规则数量不会因 Pod 数量的增加而增加。
  5. 也叫 IPVS 。

Service 的默认工作方式

创建 Pod 和 默认Service,进行默认工作状态的测试。

先创建3个 Pod

cat nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

创建一个默认类型的 Service,名称为 nginx-service

cat nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP

port: 80
是 service 在集群内部的VIP端口

targetPort: 80
是 Pod 的端口

执行创建

kubectl apply -f nginx.yaml 
kubectl apply -f nginx-service.yaml 

查看运行情况

[root@master01 ~]# kubectl get pod -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
nginx-deployment-d46f5678b-cldf4   1/1     Running   0          21m   192.10.137.153   work03              
nginx-deployment-d46f5678b-lnxh9   1/1     Running   0          21m   192.10.205.252   work01              
nginx-deployment-d46f5678b-th8xq   1/1     Running   0          21m   192.10.75.89     work02              
[root@master01 ~]# kubectl get service
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-service   ClusterIP   192.20.150.26           80/TCP    13m

查看名称为 nginx-service 的 service 成功挂载的后端 Pod

[root@master01 ~]# kubectl get endpoints nginx-service
NAME            ENDPOINTS                                             AGE
nginx-service   192.10.137.153:80,192.10.205.252:80,192.10.75.89:80   14m

可以看到我们创建的名为 nginx-service 的 Service 后端挂载了3个 Pod

给3个 Pod 写入内容,访问 Pod 时返回自身的主机名

kubectl exec nginx-deployment-d46f5678b-cldf4 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
kubectl exec nginx-deployment-d46f5678b-lnxh9 -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';
kubectl exec nginx-deployment-d46f5678b-th8xq -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html';

我们访问 Service IP 看看

[root@master01 ~]# curl 192.20.150.26
nginx-deployment-d46f5678b-th8xq
[root@master01 ~]# curl 192.20.150.26
nginx-deployment-d46f5678b-cldf4
[root@master01 ~]# curl 192.20.150.26
nginx-deployment-d46f5678b-lnxh9

可以看到 Service 成功将请求代理到了后端的一组 Pod,并且进行了流量的分配。

这是 Service 的默认工作类型,只能在集群所属的节点上访问到,离开集群后无法被访问到。

这种工作类型叫做 ClusterIP。

Service 对外提供服务的三种方式

上一节可以看到,Service 默认不对集群外部提供服务,那么如何才能在集群外部访问到呢,有三种方案。

externalIPs 方式

Service 中配置可以 externalIPs,IP 为本集群中 work 节点宿主机 IP。

apiVersion: v1
kind: Service
。。。
。。。
spec:
  。。。
  。。。
  externalIPs:
    - 192.168.10.16
    - 192.168.10.17

在 192.168.10.16/17 上执行 ss -lntp 可以看到 Service 定义的暴露端口。在集群外部访问 192.168.10.16/17 上 Service 暴露的端口即可。

NodePort 方式

改造 nginx-service.yaml,增加一行 type: NodePort

cat nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP

创建 service

kubectl apply -f nginx-service.yaml

查看运行情况

[root@master01 ~]# kubectl get service
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
nginx-service   NodePort    192.20.167.221           80:30913/TCP   13m

参数 PORT(S) 80:30913/TCP,其中 30913 就是用来集群外部访问的端口。

可以访问任何一台物理宿主机的 ip:30913 来访问到 Pod。

30913 是 K8S 从固定范围 30000-32767 中选择的,也可以通过参数 nodePort 指定固定端口。

可选择范围可以通过 kube-apiserver 的 –service-node-port-range 参数来修改。

[root@master01 ~]# ss -nltp | grep 30913
LISTEN     0      128          *:30913                    *:* 

可以看到宿主机上监听了 30913 端口。

测试

在没有运行 K8S 集群的机器上访问 K8S 宿主机
[root@192-168-10-18 ~]# curl 192.168.10.12:30913
nginx-deployment-d46f5678b-2pmts
[root@192-168-10-18 ~]# curl 192.168.10.12:30913
nginx-deployment-d46f5678b-zv8m4
[root@192-168-10-18 ~]# curl 192.168.10.12:30913
nginx-deployment-d46f5678b-2pmts

可以看到从集群外部可以成功访问到 Pod 中内容,并且为随机分配。

原理

kube-proxy 在宿主机上创建了 iptables 规则,对宿主机 IP:30913 的访问将被转发到 Service IP,然后 Service 再通过自己的 iptables 规则分发到 Pod

LoadBalancer 方式

NodePort 方式中,如果要正式对外提供服务,我们需要在集群外部再创建一个高可用的负载均衡器,以方便把流量转发到宿主机开放的端口上,如果宿主机开放端口发生了变更,我们需要手工修改前端负载均衡器。

公有云的 LoadBalancer 自动化了这一过程。

LoadBalancer 这种方式应用于公有云,提交一个 type: LoadBalancer 的 Service 创建申请后,公有云会帮我们创建一个负载均衡器,该负载均衡器会把请求直接分发给 Pod,同时 Pod IP 发生变化后,会自动更新到负载均衡器上。

其他:Headless Service

通过指定 spec.clusterIP 的值为 "None" 可以创建 Headless Service。

Headless Service 不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。

定义了 selector 的无头服务,Endpoint 控制器会在 API 中创建 Endpoints 记录, 并且修改 DNS 配置返回 A 记录,通过这个地址,请求可以直接到达 Service 的后端 Pod 上。

结束语

Service 对 IP 信息易变的 Pod 提供了服务发现、负载均衡等管理功能,同时提供了外部访问的能力,从而使外部用户能够稳定的访问到运行在集群内部的 Pod 提供的服务。

上面说的三种工作方式有如下问题:

  1. ClusterIP 方式默认工作在集群内部,使用参数 externalIPs 可指定哪个及诶按暴露端口,但无法进行7层的URL跳转等控制
  2. NodePort 方式下,全部节点都会暴露该端口,但一个端口只能对应一个业务,适合业务比较少的环境或者测试环境,业务多了以后无法有效管理
  3. LoadBalance 方式只适合于现有的公有云平台,无法用于自建集群,同时还需要额外费用

这些问题导致无法直接应用于生产环境中。

如果想提供给自建集群的生产环境使用,需要在 Service 前面再加一层 Ingress Controller。

联系我

微信公众号:zuolinux_com




推荐阅读
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • MySQL的查询执行流程涉及多个关键组件,包括连接器、查询缓存、分析器和优化器。在服务层,连接器负责建立与客户端的连接,查询缓存用于存储和检索常用查询结果,以提高性能。分析器则解析SQL语句,生成语法树,而优化器负责选择最优的查询执行计划。这一流程确保了MySQL能够高效地处理各种复杂的查询请求。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 在《Linux高性能服务器编程》一书中,第3.2节深入探讨了TCP报头的结构与功能。TCP报头是每个TCP数据段中不可或缺的部分,它不仅包含了源端口和目的端口的信息,还负责管理TCP连接的状态和控制。本节内容详尽地解析了TCP报头的各项字段及其作用,为读者提供了深入理解TCP协议的基础。 ... [详细]
  • 本文汇集了我在网络上搜集以及在实际面试中遇到的前端开发面试题目,并附有详细解答。无论是初学者还是有一定经验的开发者,都应深入理解这些问题背后的原理,通过系统学习和透彻研究,逐步形成自己的知识体系和技术框架。 ... [详细]
  • 如何在C#中配置组合框的背景颜色? ... [详细]
  • 技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告
    技术日志:使用 Ruby 爬虫抓取拉勾网职位数据并生成词云分析报告 ... [详细]
  • IOS Run loop详解
    为什么80%的码农都做不了架构师?转自http:blog.csdn.netztp800201articledetails9240913感谢作者分享Objecti ... [详细]
  • 本文介绍了几种常用的图像相似度对比方法,包括直方图方法、图像模板匹配、PSNR峰值信噪比、SSIM结构相似性和感知哈希算法。每种方法都有其优缺点,适用于不同的应用场景。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 在多线程并发环境中,普通变量的操作往往是线程不安全的。本文通过一个简单的例子,展示了如何使用 AtomicInteger 类及其核心的 CAS 无锁算法来保证线程安全。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 本文探讨了利用Python实现高效语音识别技术的方法。通过使用先进的语音处理库和算法,本文详细介绍了如何构建一个准确且高效的语音识别系统。提供的代码示例和实验结果展示了该方法在实际应用中的优越性能。相关文件可从以下链接下载:链接:https://pan.baidu.com/s/1RWNVHuXMQleOrEi5vig_bQ,提取码:p57s。 ... [详细]
  • 在交换机链路聚合中,负载均衡算法通过哈希表实现。每当创建一个新的聚合组时,交换机的底层硬件会生成一个对应的哈希表,该表存储在交换芯片上。哈希表的结构包括索引(Index)和相应的条目,这些索引由硬件支持,用于确定数据包的传输路径。通过这种方式,负载均衡算法能够高效地分配网络流量,提高链路利用率和系统性能。 ... [详细]
author-avatar
qtl4431541
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有